"""
API异常处理器
=============

统一的异常处理机制，将业务异常映射到合适的HTTP状态码。

设计原则:
- 明确的错误分类: 不同类型的错误返回不同的HTTP状态码
- 详细的错误信息: 返回结构化的错误响应
- 安全性: 不暴露敏感的内部错误信息
- 可追踪性: 记录错误日志，便于问题排查

作者: 架构组
创建日期: 2025-10-05
"""

from fastapi import Request, status
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException as StarletteHTTPException
from datetime import datetime
import logging
from typing import Dict, Any, Optional

# 导入业务异常
from ...exceptions.market_data_exceptions import (
    MarketDataException,
    DataSourceException,
    AdapterException,
    ConfigurationException,
    ValidationException,
    DataNotFoundError,
    RateLimitException,
)

# 导入适配器异常
from ..adapters.core import (
    AdapterError,
    AdapterConnectionError,
    AdapterAuthenticationError,
    AdapterDataError,
    AdapterTimeoutError,
    AdapterRateLimitError,
    AdapterConfigError,
    AdapterNotFoundError,
    AdapterNotSupportedError,
)

logger = logging.getLogger(__name__)


# ==================== 异常到HTTP状态码的映射 ====================

EXCEPTION_STATUS_MAP = {
    # 业务异常 -> HTTP状态码
    ValidationException: status.HTTP_400_BAD_REQUEST,
    DataNotFoundError: status.HTTP_404_NOT_FOUND,
    RateLimitException: status.HTTP_429_TOO_MANY_REQUESTS,
    ConfigurationException: status.HTTP_500_INTERNAL_SERVER_ERROR,
    DataSourceException: status.HTTP_503_SERVICE_UNAVAILABLE,
    AdapterException: status.HTTP_503_SERVICE_UNAVAILABLE,
    MarketDataException: status.HTTP_500_INTERNAL_SERVER_ERROR,
    
    # 适配器异常 -> HTTP状态码
    AdapterConfigError: status.HTTP_500_INTERNAL_SERVER_ERROR,
    AdapterAuthenticationError: status.HTTP_503_SERVICE_UNAVAILABLE,
    AdapterConnectionError: status.HTTP_503_SERVICE_UNAVAILABLE,
    AdapterNotFoundError: status.HTTP_404_NOT_FOUND,
    AdapterNotSupportedError: status.HTTP_501_NOT_IMPLEMENTED,
    AdapterRateLimitError: status.HTTP_429_TOO_MANY_REQUESTS,
    AdapterTimeoutError: status.HTTP_504_GATEWAY_TIMEOUT,
    AdapterDataError: status.HTTP_502_BAD_GATEWAY,
    AdapterError: status.HTTP_500_INTERNAL_SERVER_ERROR,
}


def get_status_code_for_exception(exc: Exception) -> int:
    """
    根据异常类型获取HTTP状态码
    
    Args:
        exc: 异常对象
    
    Returns:
        int: HTTP状态码
    """
    # 精确匹配
    exc_type = type(exc)
    if exc_type in EXCEPTION_STATUS_MAP:
        return EXCEPTION_STATUS_MAP[exc_type]
    
    # 检查父类
    for exception_class, status_code in EXCEPTION_STATUS_MAP.items():
        if isinstance(exc, exception_class):
            return status_code
    
    # 默认返回500
    return status.HTTP_500_INTERNAL_SERVER_ERROR


def create_error_response(
    status_code: int,
    error_type: str,
    message: str,
    details: Optional[Dict[str, Any]] = None,
    request_id: Optional[str] = None
) -> Dict[str, Any]:
    """
    创建标准化的错误响应
    
    Args:
        status_code: HTTP状态码
        error_type: 错误类型
        message: 错误消息
        details: 额外的错误详情
        request_id: 请求ID（用于追踪）
    
    Returns:
        Dict: 错误响应字典
    """
    response = {
        "success": False,
        "error": {
            "type": error_type,
            "message": message,
            "status_code": status_code,
            "timestamp": datetime.now().isoformat(),
        }
    }
    
    if details:
        response["error"]["details"] = details
    
    if request_id:
        response["error"]["request_id"] = request_id
    
    return response


# ==================== 异常处理器 ====================

async def market_data_exception_handler(
    request: Request,
    exc: MarketDataException
) -> JSONResponse:
    """
    处理MarketDataException及其子类
    
    Args:
        request: FastAPI请求对象
        exc: 异常对象
    
    Returns:
        JSONResponse: JSON错误响应
    """
    status_code = get_status_code_for_exception(exc)
    error_type = exc.__class__.__name__
    
    # 记录错误日志
    if status_code >= 500:
        logger.error(
            f"{error_type}: {str(exc)}",
            exc_info=True,
            extra={"path": request.url.path, "method": request.method}
        )
    else:
        logger.warning(
            f"{error_type}: {str(exc)}",
            extra={"path": request.url.path, "method": request.method}
        )
    
    # 创建错误响应
    response = create_error_response(
        status_code=status_code,
        error_type=error_type,
        message=str(exc),
        details=getattr(exc, "details", None),
        request_id=request.headers.get("X-Request-ID")
    )
    
    return JSONResponse(
        status_code=status_code,
        content=response
    )


async def adapter_exception_handler(
    request: Request,
    exc: AdapterError
) -> JSONResponse:
    """
    处理AdapterError及其子类
    
    Args:
        request: FastAPI请求对象
        exc: 异常对象
    
    Returns:
        JSONResponse: JSON错误响应
    """
    status_code = get_status_code_for_exception(exc)
    error_type = exc.__class__.__name__
    
    # 记录错误日志
    if status_code >= 500:
        logger.error(
            f"Adapter {error_type}: {str(exc)}",
            exc_info=True,
            extra={"path": request.url.path, "method": request.method}
        )
    else:
        logger.warning(
            f"Adapter {error_type}: {str(exc)}",
            extra={"path": request.url.path, "method": request.method}
        )
    
    # 创建用户友好的错误消息
    user_message = _get_user_friendly_message(exc)
    
    # 创建错误响应
    response = create_error_response(
        status_code=status_code,
        error_type=error_type,
        message=user_message,
        details={"original_error": str(exc)} if status_code < 500 else None,
        request_id=request.headers.get("X-Request-ID")
    )
    
    return JSONResponse(
        status_code=status_code,
        content=response
    )


async def validation_exception_handler(
    request: Request,
    exc: RequestValidationError
) -> JSONResponse:
    """
    处理FastAPI请求验证错误
    
    Args:
        request: FastAPI请求对象
        exc: 验证异常对象
    
    Returns:
        JSONResponse: JSON错误响应
    """
    logger.warning(
        f"Validation error: {exc.errors()}",
        extra={"path": request.url.path, "method": request.method}
    )
    
    # 格式化验证错误
    validation_errors = []
    for error in exc.errors():
        validation_errors.append({
            "field": ".".join(str(loc) for loc in error["loc"]),
            "message": error["msg"],
            "type": error["type"]
        })
    
    response = create_error_response(
        status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
        error_type="ValidationError",
        message="请求参数验证失败",
        details={"validation_errors": validation_errors},
        request_id=request.headers.get("X-Request-ID")
    )
    
    return JSONResponse(
        status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
        content=response
    )


async def http_exception_handler(
    request: Request,
    exc: StarletteHTTPException
) -> JSONResponse:
    """
    处理HTTP异常
    
    Args:
        request: FastAPI请求对象
        exc: HTTP异常对象
    
    Returns:
        JSONResponse: JSON错误响应
    """
    logger.warning(
        f"HTTP {exc.status_code}: {exc.detail}",
        extra={"path": request.url.path, "method": request.method}
    )
    
    response = create_error_response(
        status_code=exc.status_code,
        error_type="HTTPException",
        message=str(exc.detail),
        request_id=request.headers.get("X-Request-ID")
    )
    
    return JSONResponse(
        status_code=exc.status_code,
        content=response
    )


async def generic_exception_handler(
    request: Request,
    exc: Exception
) -> JSONResponse:
    """
    处理未捕获的通用异常
    
    Args:
        request: FastAPI请求对象
        exc: 异常对象
    
    Returns:
        JSONResponse: JSON错误响应
    """
    logger.error(
        f"Unhandled exception: {str(exc)}",
        exc_info=True,
        extra={"path": request.url.path, "method": request.method}
    )
    
    # 不暴露内部错误详情给客户端
    response = create_error_response(
        status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
        error_type="InternalServerError",
        message="服务器内部错误，请稍后重试",
        request_id=request.headers.get("X-Request-ID")
    )
    
    return JSONResponse(
        status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
        content=response
    )


# ==================== 辅助函数 ====================

def _get_user_friendly_message(exc: AdapterError) -> str:
    """
    将适配器异常转换为用户友好的消息
    
    Args:
        exc: 适配器异常
    
    Returns:
        str: 用户友好的错误消息
    """
    if isinstance(exc, AdapterConnectionError):
        return "数据源连接失败，请稍后重试"
    elif isinstance(exc, AdapterAuthenticationError):
        return "数据源认证失败，请检查配置"
    elif isinstance(exc, AdapterTimeoutError):
        return "数据源请求超时，请稍后重试"
    elif isinstance(exc, AdapterRateLimitError):
        return "请求过于频繁，请稍后重试"
    elif isinstance(exc, AdapterNotFoundError):
        return "请求的数据不存在"
    elif isinstance(exc, AdapterNotSupportedError):
        return "数据源不支持此操作"
    elif isinstance(exc, AdapterDataError):
        return "数据源返回数据异常"
    else:
        return "数据源服务异常，请稍后重试"


# ==================== 注册异常处理器的辅助函数 ====================

def register_exception_handlers(app):
    """
    注册所有异常处理器到FastAPI应用
    
    Args:
        app: FastAPI应用实例
    
    Example:
        ```python
        from fastapi import FastAPI
        from app.api.exception_handlers import register_exception_handlers
        
        app = FastAPI()
        register_exception_handlers(app)
        ```
    """
    # 注册业务异常处理器
    app.add_exception_handler(MarketDataException, market_data_exception_handler)
    
    # 注册适配器异常处理器
    app.add_exception_handler(AdapterError, adapter_exception_handler)
    
    # 注册FastAPI内置异常处理器
    app.add_exception_handler(RequestValidationError, validation_exception_handler)
    app.add_exception_handler(StarletteHTTPException, http_exception_handler)
    
    # 注册通用异常处理器（捕获所有未处理的异常）
    app.add_exception_handler(Exception, generic_exception_handler)
    
    logger.info("异常处理器注册完成")
